#ifndef __RATELIMIT_H__
#define __RATELIMIT_H__

#include "spdlimit.h"
#include "port.h"

/*
Currently, ratelimit only works on write, doing ratelimit on read will have some potential issues for the data is already
readed by the real connection. For UDP, it doesn't matter, but for TCP it will cause packet loss at the APP level, which
is not what the user's want.

Notice, the packet can be splitted into smaller sub-packets, it won't cause problems for APP for TCP but will have potential
issue for UDP, if a UDP PDU is splitted, if one sub packets drops, then the remains parts becomes invalid.

So, do set splitable to false when the real connection is UDP.

No Buffer Here!!
*/

class RatelimitConn : public IConnection, public ITokenBucketListner
{
public:
	RatelimitConn(Connection* pConn, bool splitable);
	virtual ~RatelimitConn();

	virtual uint16 GetConvId() { return real_conn_?real_conn_->GetConvId():-1; }

	void SetRateLimit(uint32 limit);//Bytes/sec

	//////////////////////////////////////////////////////////////////////////
	//IConnection
	virtual int Send(byte* data, size_t size);

	//Set interval of probing, if set to INT_MAX, will disable active probing, but still can process probing packets
	//Default 10 ms
	virtual void SetProbingInterval(int ms);

	virtual bool IsTimetoPing(uint32 now);

	//The ping can be sent using APP data or Ping packets
	//The default connection use Ping packets, but if the buffered connection, it can use ADD data, simply sent data
	//out, and the underlying connection will decide automatically, if failed, should cope with the failure, and try
	//ping when OnWrite Callbacked.
	virtual void DoPing();

	virtual bool Connected() const;


	//if disabled, the connection will not process probing packets and will forward all data read to the app layer
	virtual void EnablePing(bool enabled);

	virtual PROTO_TYPE GetProtoType();

	virtual const SocketAddress& RemoteAddress();

	//////////////////////////////////////////////////////////////////////////
	//ITokenBucketListner

	virtual void OnTokenFilled(TokenBucket * pBucket);
	virtual void OnTokenEmpty(TokenBucket * pBucket);


private:
	Connection * real_conn_;
	bool splitable_;

	TokenBucketCfg rate_cfg_;
	TokenBucket send_bucket_;
};

#endif//__RATELIMIT_H__